package net.bingosoft.common;

import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.sql.Clob;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.bingosoft.common.config.Config;
import net.bingosoft.common.json.JSONArray;
import net.bingosoft.common.json.JSONConverter;
import net.bingosoft.common.util.ClassUtil;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.DynaBean;
import org.apache.commons.beanutils.DynaClass;
import org.apache.commons.beanutils.DynaProperty;
import org.apache.commons.beanutils.MappedPropertyDescriptor;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 2007-8-8 下午12:06:57
 * Author:yangdongyu(yangdy@bingosoft.net)
 * ReadMe:bean 工具类,提供对bean的基本操作
 * ChangeLog:
 */
public final class BeanHelper extends BeanUtils{

	private static final Log log = LogFactory.getLog(BeanHelper.class);
	private static final DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	private static final DateFormat ldf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	private static final DateFormat defaultFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy",Locale.ENGLISH);
	private static final DateFormat gmtTimeFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss yyyy",Locale.ENGLISH);
	private static final  DateFormat dateIdFormate = new SimpleDateFormat("yyyyMMddHHmmss");
	private static final String NUMBER_FORMAT = Config.getString("NUMBER_FORMAT","############0.00");
	private static final NumberFormat nf = new DecimalFormat(NUMBER_FORMAT);
	private BeanHelper(){}

	/**
	 * 日期解析
	 * @param date
	 * @return
	 */
	public static Date parseDate(String date){
		if(date == null || date.trim().equals("")){
			return null;
		}
		Date d = null;
		try{
			if(date.contains(" CST")){//ChinaStardardTime
				try{
					d = defaultFormat.parse(date);
				}catch(ParseException e){}
			}else if(date.contains(" GMT+08:00")){
				date = date.replace(" GMT+08:00", "");
				d = gmtTimeFormat.parse(date);
			}else if(date.length() > 10){
				d = ldf.parse(date);
			}else{
				d = sdf.parse(date);
			}
		}catch(Exception ex){
			throw new RuntimeException("无法解析的日期字符串 : " + date);
		}
		return d;
	}
	/**
	 * 格式化日期,根据时分秒是否为空自动选择使用格式 yyyy-MM-dd 或 yyyy-MM-dd HH:mm:ss
	 * @param date
	 * @return
	 */
	public static String formatDate(Date date){
		if(date == null) return null;
		String d = null;
		Calendar c = Calendar.getInstance();
		c.setTime(date);
		try{
			if(c.get(Calendar.HOUR) > 0 || c.get(Calendar.MINUTE) > 0 ||c.get(Calendar.SECOND) > 0){
				d = ldf.format(date);	
			}else{
				d = sdf.format(date);	
			}
		}catch(Exception ex){
			throw new RuntimeException("无法格式化的日期 : " + date);
		}
		return d;
	}
	/**
	 * 复制Bean属性,根据要进行拷贝的源和目标的数据类型自动完成数据转换
	 * @param src 源对象
	 * @param dest 目标对象
	 * @param ignoreNull 是否忽略空的属性
	 */
	@SuppressWarnings("unchecked")
	public static void copyProperties(Object dest,Object src,boolean ignoreNull) {
		try {
			Set fromPropertys = BeanUtils.describe(src).keySet();
			Set toPropertys = BeanUtils.describe(dest).keySet();
			for (Object oPropertyName : fromPropertys) {
				String propertyName = oPropertyName.toString();
				if (!propertyName.equals("class")) {
					if (toPropertys.contains(propertyName)) {
						Object valueToBeCopied = PropertyUtils.getNestedProperty(src, propertyName);						
						Class srcDataType = PropertyUtils.getPropertyDescriptor(src, propertyName).getPropertyType();
						Class destDataType = PropertyUtils.getPropertyDescriptor(dest, propertyName).getPropertyType();
						if(valueToBeCopied == null){
							 if(!ignoreNull){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
							 }
							 continue;
						}
						if(srcDataType == destDataType){//源类型和目标类型一致,不需转换,直接复制
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
							continue;
						}else if(srcDataType == String.class){//源类型为字符串
							valueToBeCopied = ConvertUtils.convert((String)valueToBeCopied, destDataType);
						}else if(destDataType == String.class){//目标类型为字符串
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied);
						}else if(ClassUtil.isPrimitiveOrWrapper(srcDataType) || Number.class.isAssignableFrom(destDataType)){
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied.toString(), destDataType);	
						}
						if(valueToBeCopied == null){
//							 if(!ignoreNull){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
//							 }
							 continue;
						}
						if(destDataType.isInstance(valueToBeCopied)) {
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
						}else{
							log.error("属性[" + propertyName + "]源数据类型[" + valueToBeCopied.getClass().getName() + "]和目标数据类型["+destDataType.getName()+"]不匹配,忽略此次赋值");
						}
					}
				}

			}
		} catch (Exception e) {
			throw new RuntimeException("复制属性出错 ...",e);
		} 
	}
	/**
	 * 复制Bean属性,根据要进行拷贝的源和目标的数据类型自动完成数据转换
	 * @param src 源对象
	 * @param dest 目标对象
	 * @param forceInjectProps 需要强制注入的属性(不管属性是否为空(null),都进行复制,优先于ignoreNull)
	 * @param ignoreNull 是否忽略空的属性
	 */
	public static void copyProperties(Object dest,Object src,boolean ignoreNull,String ...forceInjectProps) {
		try {
			Set fromPropertys = BeanUtils.describe(src).keySet();
			Set toPropertys = BeanUtils.describe(dest).keySet();
			String includeProps = StringUtils.join(forceInjectProps,",");
			for (Object oPropertyName : fromPropertys) {
				String propertyName = oPropertyName.toString();
				if (!propertyName.equals("class")) {
					if (toPropertys.contains(propertyName)) {
						Object valueToBeCopied = PropertyUtils.getNestedProperty(src, propertyName);						
						Class srcDataType = PropertyUtils.getPropertyDescriptor(src, propertyName).getPropertyType();
						Class destDataType = PropertyUtils.getPropertyDescriptor(dest, propertyName).getPropertyType();
						if(valueToBeCopied == null){
							 if(!ignoreNull || includeProps.contains(propertyName)){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
							 }
							 continue;
						}
						if(srcDataType == destDataType){//源类型和目标类型一致,不需转换,直接复制
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
							continue;
						}else if(srcDataType == String.class){//源类型为字符串
							valueToBeCopied = ConvertUtils.convert((String)valueToBeCopied, destDataType);
						}else if(destDataType == String.class){//目标类型为字符串
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied);
						}else if(ClassUtil.isPrimitiveOrWrapper(srcDataType) || Number.class.isAssignableFrom(destDataType)){
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied.toString(), destDataType);	
						}
						if(valueToBeCopied == null){
							 if(!ignoreNull || includeProps.contains(propertyName)){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
							 }
							 continue;
						}
						if(destDataType.isInstance(valueToBeCopied)) {
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
						}else{
							log.error("属性[" + propertyName + "]源数据类型[" + valueToBeCopied.getClass().getName() + "]和目标数据类型["+destDataType.getName()+"]不匹配,忽略此次赋值");
						}
					}
				}

			}
		} catch (Exception e) {
			throw new RuntimeException("复制属性出错 ...",e);
		} 
	}
	
	/**
	 * 复制Bean属性,根据要进行拷贝的源和目标的数据类型自动完成数据转换
	 * @param src 源对象
	 * @param dest 目标对象
	 * @param ignoreNull 是否忽略空的属性
	 * @param ignoredPropertis 忽略的属性,用','分割
	 */
	@SuppressWarnings("unchecked")
	public static void copyProperties(Object dest,Object src,boolean ignoreNull,String ignoredPropertis) {
		try {
			Set fromPropertys = BeanUtils.describe(src).keySet();
			Set toPropertys = BeanUtils.describe(dest).keySet();
			for (Object oPropertyName : fromPropertys) {
				String propertyName = oPropertyName.toString();
				if (!propertyName.equals("class")) {
					if (!ignoredPropertis.contains(propertyName) && toPropertys.contains(propertyName)) {
						Object valueToBeCopied = PropertyUtils.getNestedProperty(src, propertyName);						
						Class srcDataType = PropertyUtils.getPropertyDescriptor(src, propertyName).getPropertyType();
						Class destDataType = PropertyUtils.getPropertyDescriptor(dest, propertyName).getPropertyType();
						if(valueToBeCopied == null){
							 if(!ignoreNull){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
							 }
							 continue;
						}
						if(srcDataType == destDataType){//源类型和目标类型一致,不需转换,直接复制
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
							continue;
						}else if(srcDataType == String.class){//源类型为字符串
							valueToBeCopied = ConvertUtils.convert((String)valueToBeCopied, destDataType);
						}else if(destDataType == String.class){//目标类型为字符串
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied);
						}else if(ClassUtil.isPrimitiveOrWrapper(srcDataType) || Number.class.isAssignableFrom(destDataType)){
							valueToBeCopied = ConvertUtils.convert(valueToBeCopied.toString(), destDataType);	
						}
						if(valueToBeCopied == null){
//							 if(!ignoreNull){
								 PropertyUtils.setNestedProperty(dest, propertyName,null);
//							 }
							 continue;
						}
						if(destDataType.isInstance(valueToBeCopied)) {
							PropertyUtils.setNestedProperty(dest, propertyName,valueToBeCopied);
						}else{
							log.error("属性[" + propertyName + "]源数据类型[" + valueToBeCopied.getClass().getName() + "]和目标数据类型["+destDataType.getName()+"]不匹配,忽略此次赋值");
						}
					}
				}

			}
		} catch (Exception e) {
			throw new RuntimeException("复制属性出错 ...",e);
		} 
	}
	/**
	 * 复制属性,忽略空的属性
	 * @param dest 属性复制的目标对象
	 * @param src 属性复制的来源
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static void copyProperties(Object dest, Object src)throws IllegalAccessException, InvocationTargetException {
		copyProperties(dest, src,true);
	}
	/**
	 * 将传入对象转换成一个Integer
	 * @param src
	 * @param defaultValue
	 * @return
	 */
	public static Integer getInt(Object src,Integer defaultValue){
		if(src == null || src.toString().trim().equals("")){
			return defaultValue;
		}else{
			Integer result = null;
			try{
				result = Integer.valueOf(src.toString());
			}catch (Exception e) {
				result = defaultValue;

			}
			return result;
		}
	}
	/**
	 * 根据传入的obj 获取一个String类型的数据
	 * @param src 传入对象
	 * @param defaultValue 当obj为null时返回的默认字符串
	 * @return
	 */
	public static String getString(Object src,String defaultValue){
		return src == null ? defaultValue : src.toString();
	}
	/**
	 * 将传入对象转换成Long类型数据
	 * @param src
	 * @param defaultValue
	 * @return
	 */
	public static Long getLong(Object src,Long defaultValue){
		if(src == null || src.toString().trim().equals("")){
			return defaultValue;
		}else{
			Long result = null;
			try{
				result = Long.valueOf(src.toString());
			}catch (Exception e) {
				result = defaultValue;

			}
			return result;
		}
	}
	/**
	 * 将传入对象转换成Float对象返回
	 * @param src
	 * @param defaultValue
	 * @return
	 */
	public static Float getFloat(Object src,Float defaultValue){
		if(src == null || src.toString().trim().equals("")){
			return defaultValue;
		}else{
			Float result = null;
			try{
				result = Float.valueOf(src.toString());
			}catch (Exception e) {
				result = defaultValue;
			}
			return result;
		}
	}
	/**
	 * 将传入对象转换成double类型对象
	 * @param src
	 * @param defaultValue
	 * @return
	 */
	public static Double getDouble(Object src,Double defaultValue){
		if(src == null || src.toString().trim().equals("")){
			return defaultValue;
		}else{
			Double result = null;
			try{
				result = Double.valueOf(src.toString());
			}catch (Exception e) {
				result = defaultValue;
			}
			return result;
		}
	}

	/**
	 * 获取一个整数,默认值为 0
	 * @param src
	 * @return
	 */
	public static Integer getInt(Object src){
		return getInt(src,0);
	}
	/**
	 * 获取一个Long,默认值为 0
	 * @param src
	 * @return
	 */
	public static Long getLong(Object src){
		return getLong(src,0L);
	}
	/**
	 * 获取一个Float,默认值为 0
	 * @param src
	 * @return
	 */
	public static Float getFloat(Object src){
		return getFloat(src,0.0F);
	}
	/**
	 * 获取一个Double,默认值为 0
	 * @param src
	 * @return
	 */
	public static Double getDouble(Object src){
		return getDouble(src,0.0);
	}
	/**
	 * 获取非空字符串
	 * @param src
	 * @return
	 */
	public static String getNotNullString(Object src){
		return (src == null)? "":String.valueOf(src);
	}
	/**
	 * 获取bean中的属性,不做任何类型任何转换
	 * @param bean
	 * @param propertyName
	 * @return
	 * @throws Exception
	 */
	public static Object getRawProperty(Object bean,String propertyName)throws IllegalAccessException, InvocationTargetException,NoSuchMethodException {
		return PropertyUtils.getProperty(bean, propertyName);
	}
	/**
	 * 获取bean中的属性,并将结果转换成String类型
	 * @param bean
	 * @param propertyName
	 * @return
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 */
	public static String getPropertyAsString(Object bean,String propertyName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
		return getProperty(bean, propertyName);
	}


	/**
	 * 将对象的属性放置到Map中
	 * @param src
	 * @return
	 * @throws Exception
	 */
	public static Map Object2Map(Object src) throws Exception{
		return describe(src);
	}
	
	
    /**
     * Return the entire set of properties for which the specified bean
     * provides a read method.  This map can be fed back to a call to
     * <code>BeanUtils.populate()</code> to reconsitute the same set of
     * properties, modulo differences for read-only and write-only
     * properties, but only if there are no indexed properties.
     *
     * @param bean Bean whose properties are to be extracted
     *
     * @exception IllegalAccessException if the caller does not have
     *  access to the property accessor method
     * @exception InvocationTargetException if the property accessor method
     *  throws an exception
     * @exception NoSuchMethodException if an accessor method for this
     *  propety cannot be found
     */
    public static Map describe(Object bean)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {
    	
        if (bean == null) {
        //            return (Collections.EMPTY_MAP);
            return (new java.util.HashMap());
        }
        
        if (log.isDebugEnabled()) {
            log.debug("Describing bean: " + bean.getClass().getName());
        }
            
        Map<String, Object> description = new HashMap<String, Object>();
        if (bean instanceof DynaBean) {
            DynaProperty descriptors[] =
                ((DynaBean) bean).getDynaClass().getDynaProperties();
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if("class".equals(name))continue;
                description.put(name, getRawProperty(bean, name));
            }
        } else {
            PropertyDescriptor descriptors[] =
                PropertyUtils.getPropertyDescriptors(bean);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if("class".equals(name))continue;
                if (descriptors[i].getReadMethod() != null)
                    description.put(name, getRawProperty(bean, name));
            }
        }
        return (description);

    }
	/**
	 * 将 Map 中和 target 的同名属性复制到 target 对象中
	 * @param map
	 * @param target
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws Exception
	 */
	public static <T> T  Map2Object(Map map,T target) throws IllegalAccessException, InvocationTargetException {
		populate(target, map);
		return target;
	}
	/**
	 * 将 Map 中和 target 的同名属性(忽略大小写,忽略下划线)复制到 target 对象中
	 * 例如 : 将ibatis从数据库查询出的结果放入target
	 * @param map 查询结果
	 * @param target 目标对象
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	 * @throws IllegalArgumentException 
	 * @throws Exception
	 */
	public static <T> T Map2ObjectIgnoreCase(Map<String,Object> map,T target) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		if ((target == null) || (map == null)) {
			return null;
		}
		Iterator names = map.keySet().iterator();
		PropertyDescriptor [] descriptors = PropertyUtils.getPropertyDescriptors(target);
		while (names.hasNext()) {
			String name = (String) names.next();
			if (name == null || name.equals("")) {
				continue;
			}
			for(PropertyDescriptor des : descriptors){
				if(des.getName().equalsIgnoreCase(name) || des.getName().equalsIgnoreCase(name.replaceAll("_", ""))){
					Object value = map.get(name);
					if(value == null){
						des.getWriteMethod().invoke(target, new Object[]{ null });
					}else{
						Class propertyType = des.getPropertyType();
						if(propertyType == value.getClass()){
							setProperty(target,des.getName(), value);	
						}else if(value instanceof String){
							setProperty(target,des.getName(), ConvertUtils.convert((String)value, propertyType));	
						}else if(propertyType == String.class){
							setProperty(target,des.getName(), ConvertUtils.convert(value));	
						}else if(ClassUtil.isPrimitiveOrWrapper(propertyType) || value instanceof Number){
							setProperty(target,des.getName(), ConvertUtils.convert(String.valueOf(value),propertyType));	
						}else if(propertyType == Calendar.class || value instanceof Date){
							Calendar c = Calendar.getInstance();
							c.setTime((Date)value);
							setProperty(target,des.getName(), c);	
						}else if(propertyType == Date.class || value instanceof Calendar){
							setProperty(target,des.getName(), ((Calendar)value).getTime());	
						}else{
							log.warn("Map 中" + name + "的属性类型["+value.getClass().getName()+"]和目标对象中的数据类型["+propertyType.getName()+"]不匹配,忽略此次赋值...");
						}
					}
					break;
				}
			}
		}
		return target;
	}
	/**
	 * 将Map中键值含有指定前缀的属性放入的指定对象的属性中去,对象的属性名称不包括前缀
	 * @param <T>
	 * @param map 
	 * @param target
	 * @param keyFilterPrefix
	 * @return
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T Map2ObjectIgnoreCase(Map<String,Object> map,T target,String keyFilterPrefix) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		if ((target == null) || (map == null)) {
			return null;
		}
		Map<String,Object> subMap = new HashMap<String,Object>();
		int prefixLengh = keyFilterPrefix == null ? 0 : keyFilterPrefix.length();
		for(Iterator<String> it = map.keySet().iterator();it.hasNext();){
			String key = it.next();
			if(key.startsWith(keyFilterPrefix)){
				subMap.put(key.substring(prefixLengh), map.get(key));
			}
		}
		Map2ObjectIgnoreCase(subMap, target);
		return target;
	}
	/**
	 * 格式化数字
	 * @param number
	 * @return
	 */
	public static String formatNumber(Object number) {
		if(number != null || number instanceof Number) {
			return nf.format(number);
		}
		return "";
	}

	/**
	 * 将对象转换成对应的字符串表示
	 * @param value
	 * @return
	 * @throws SQLException 
	 */
	public static String converToString(Object value) {
		if(value == null) return "";
		if(value instanceof String) return (String)value;
		if(value instanceof Date){
			return formatDate((Date)value);
		}else if(value instanceof Double){
			return formatNumber(value);
		}else if(value instanceof Clob){
			Clob v = (Clob)value;
			try {
				return v.getSubString(1, (int)v.length());
			} catch (SQLException e) {
				log.debug("读取SQL的Clob字段时发生错误",e);
				throw new RuntimeException("读取SQL的Clob字段时发生错误",e);
			}
		}else{
			String result= String.valueOf(value);
			return result;
		}	
	}
	/**
	 * 将给定的数组对象用给定的seperator连接起来作为字符串返回
	 * @param seperator
	 * @param strings
	 * @return
	 */
	public static String join(Object[] array,String separator) {
		return StringUtils.join(array, separator == null ? ",":separator);
	}
	/**
	 * 获取非空的Long 类型的值
	 * @param src
	 * @return
	 */
	public static Long getNotNullLong(Long src){
		return src == null ? 0L : src;
	}
	/**
	 * 对模板字符串进行格式化,如模板字符串为:My name is @{name},I am @{age} years old.
	 * 如果传入的valueBean(可以是POJO或Map)中含有对应的name和age属性,如为 Rain,25 那么
	 * 该方法将返回 My name is Rain,I am 25 years old.
	 * @param template 模板字符串,其中@{属性名} 为模板字符串中变量的定义方法
	 * @param start 起始匹配位置,一般应为 0
	 * @param valueBean 包含模板变量的对象
	 * @return 格式化之后的模板字符串
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static String format(String template,int start ,Object valueBean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
		if(StringUtils.isEmpty(template)) return null;
		Matcher m = Pattern.compile("\\@\\{(\\w+)\\}").matcher(template);
		if(m.find(start)){
			String property = m.group(1).trim();
			if(StringUtils.isNotEmpty(property) && valueBean != null){				
				try{
					if(valueBean instanceof Map){
						property = ((Map)valueBean).get(property).toString();
					}else{
						property = BeanHelper.getPropertyAsString(valueBean, property);	
					}
				}catch(Exception ex){
					property = "undefined";
				}
			}
			return format(m.replaceFirst(property),m.end(),valueBean);		
		}
		return template;
	}
	/**
     * Filter the specified string for characters that are sensitive to
     * HTML interpreters, returning the string with these characters replaced
     * by the corresponding character entities.
     *
     * @param value The string to be filtered and returned
     */
    public static String filter(String value) {

        if (value == null || value.length() == 0) {
            return value;
        }

        StringBuffer result = null;
        String filtered = null;
        for (int i = 0; i < value.length(); i++) {
            filtered = null;
            switch (value.charAt(i)) {
                case '<':
                    filtered = "&lt;";
                    break;
                case '>':
                    filtered = "&gt;";
                    break;                
            }

            if (result == null) {
                if (filtered != null) {
                    result = new StringBuffer(value.length() + 50);
                    if (i > 0) {
                        result.append(value.substring(0, i));
                    }
                    result.append(filtered);
                }
            } else {
                if (filtered == null) {
                    result.append(value.charAt(i));
                } else {
                    result.append(filtered);
                }
            }
        }
        return result == null ? value : result.toString();
    }
    /**
     * 将查询参数放入sql/hql中
     * @param 查询语句(sql/hql)
     * @param params 参数数组或参数map
     * @return
     */
    public static String prepareSQL(String sql,Object ...params){
    	if(params.length == 1 && params[0] instanceof Map){
    		Map paramsMap = (Map)params[0];
    		for(Object key : paramsMap.keySet()){
    			sql = sql.replaceAll(":" + key, converToString(paramsMap.get(key)));
    		}
    	}else{
    		int i = 0;
    		while(sql.contains("?") && i < params.length){
    			sql = sql.replaceFirst("\\?", "'" + converToString(params[i++])+ "'");
    		}
    	}
    	return sql;
    }
    /**
     * 将一个对象转换成json字符串
     * @param o
     * @return
     * @throws Exception 
     */
    public static String toJSONString(Object o,String ...excludeProperties) throws Exception{
    	return JSONConverter.toJSON(o, null,excludeProperties).toString();
    }
    /**
     * 根据当前时间生成标识
     * @return
     */
	public static String generateIdByDate(){
		return dateIdFormate.format(new Date());
	}
	
	/**
	 * 将String类型的值转换成指定类型的对象
	 * @param srcString
	 * @param targetType
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static<T> T toTargetType(String srcString,Class<T> targetType){
		srcString = srcString == null ? "" :srcString.trim();
		Object targetJavaBean = null;
		if (targetType == Integer.class ||targetType == int.class  ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Integer(0);
			} else {
				targetJavaBean = new Integer(srcString);
			}
		} else if (targetType == Long.class ||targetType == long.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Long(0);
			} else {
				targetJavaBean = new Long(srcString);
			}
		} else if (targetType == Short.class ||targetType == short.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Short((short) 0);
			} else {
				targetJavaBean = new Short(srcString);
			}
		} else if (targetType == Byte.class ||targetType == byte.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Byte((byte) 0);
			} else {
				targetJavaBean = new Byte(srcString);
			}
		} else if (targetType == Float.class ||targetType == float.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Float(0);
			} else {
				targetJavaBean = new Float(srcString);
			}
		} else if (targetType == Double.class ||targetType == double.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Double(0);
			} else {
				targetJavaBean = new Double(srcString);
			}
		} else if (targetType == Boolean.class ||targetType == boolean.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Boolean(false);
			} else {
				targetJavaBean = new Boolean(srcString);
			}
		} else if (targetType == String.class ) {
			targetJavaBean = srcString;
		} else if (targetType == Character.class ||targetType == char.class ) {
			if ("".equals(srcString)) {
				targetJavaBean = new Character(' ');
			} else {
				targetJavaBean = new Character(srcString.charAt(0));
			}
		} else if (targetType == Date.class){
			targetJavaBean = parseDate(srcString);
		}
		if(targetJavaBean.getClass() != targetType ){
			throw new RuntimeException("can not convert string value : " + srcString + " to targetType : " + targetType.getName());
		}
		return (T)targetJavaBean;
	}
	/**
	 * 判断给定对象是否为空
	 * @param o
	 * @return
	 */
    public static boolean isNull(Object o) {
        if (o instanceof String) {
            String s = (String) o;
            return (s == null) || (s.length() == 0);
        } else if (o instanceof JSONArray) {
            JSONArray jsonArray = (JSONArray) o;
            return (jsonArray == null) || (jsonArray.length() == 0);
        } else {
            return (o == null);
        }
    }
    /**
     * <p>Set the specified property value, performing type conversions as
     * required to conform to the type of the destination property.</p>
     *
     * <p>If the property is read only then the method returns 
     * without throwing an exception.</p>
     *
     * <p>If <code>null</code> is passed into a property expecting a primitive value,
     * then this will be converted as if it were a <code>null</code> string.</p>
     *
     * <p><strong>WARNING</strong> - The logic of this method is customized
     * to meet the needs of <code>populate()</code>, and is probably not what
     * you want for general property copying with type conversion.  For that
     * purpose, check out the <code>copyProperty()</code> method instead.</p>
     *
     * @param bean Bean on which setting is to be performed
     * @param name Property name (can be nested/indexed/mapped/combo)
     * @param value Value to be set
     *
     * @exception IllegalAccessException if the caller does not have
     *  access to the property accessor method
     * @exception InvocationTargetException if the property accessor method
     *  throws an exception
     */
    public static void setProperty(Object bean, String name, Object value)
        throws IllegalAccessException, InvocationTargetException {

        // Trace logging (if enabled)
        if (log.isTraceEnabled()) {
            StringBuffer sb = new StringBuffer("  setProperty(");
            sb.append(bean);
            sb.append(", ");
            sb.append(name);
            sb.append(", ");
            if (value == null) {
                sb.append("<NULL>");
            } else if (value instanceof String) {
                sb.append((String) value);
            } else if (value instanceof String[]) {
                String values[] = (String[]) value;
                sb.append('[');
                for (int i = 0; i < values.length; i++) {
                    if (i > 0) {
                        sb.append(',');
                    }
                    sb.append(values[i]);
                }
                sb.append(']');
            } else {
                sb.append(value.toString());
            }
            sb.append(')');
            log.trace(sb.toString());
        }

        // Resolve any nested expression to get the actual target bean
        Object target = bean;
        int delim = name.lastIndexOf(PropertyUtils.NESTED_DELIM);
        if (delim >= 0) {
            try {
                target =
                    PropertyUtils.getProperty(bean, name.substring(0, delim));
            } catch (NoSuchMethodException e) {
                return; // Skip this property setter
            }
            name = name.substring(delim + 1);
            if (log.isTraceEnabled()) {
                log.trace("    Target bean = " + target);
                log.trace("    Target name = " + name);
            }
        }

        // Declare local variables we will require
        String propName = null;          // Simple name of target property
        Class type = null;               // Java type of target property
        int index = -1;                  // Indexed subscript value (if any)
        String key = null;               // Mapped key value (if any)

        // Calculate the property name, index, and key values
        propName = name;
        int i = propName.indexOf(PropertyUtils.INDEXED_DELIM);
        if (i >= 0) {
            int k = propName.indexOf(PropertyUtils.INDEXED_DELIM2);
            try {
                index =
                    Integer.parseInt(propName.substring(i + 1, k));
            } catch (NumberFormatException e) {
                ;
            }
            propName = propName.substring(0, i);
        }
        int j = propName.indexOf(PropertyUtils.MAPPED_DELIM);
        if (j >= 0) {
            int k = propName.indexOf(PropertyUtils.MAPPED_DELIM2);
            try {
                key = propName.substring(j + 1, k);
            } catch (IndexOutOfBoundsException e) {
                ;
            }
            propName = propName.substring(0, j);
        }

        // Calculate the property type
        if (target instanceof DynaBean) {
            DynaClass dynaClass = ((DynaBean) target).getDynaClass();
            DynaProperty dynaProperty = dynaClass.getDynaProperty(propName);
            if (dynaProperty == null) {
                return; // Skip this property setter
            }
            type = dynaProperty.getType();
        } else {
            PropertyDescriptor descriptor = null;
            try {
                descriptor =
                    PropertyUtils.getPropertyDescriptor(target, name);
                if (descriptor == null) {
                    return; // Skip this property setter
                }
            } catch (NoSuchMethodException e) {
                return; // Skip this property setter
            }
            if (descriptor instanceof MappedPropertyDescriptor) {
                if (((MappedPropertyDescriptor) descriptor).getMappedWriteMethod() == null) {
                    if (log.isDebugEnabled()) {
                        log.debug("Skipping read-only property");
                    }
                    return; // Read-only, skip this property setter
                }
                type = ((MappedPropertyDescriptor) descriptor).
                    getMappedPropertyType();
            } else if (descriptor instanceof IndexedPropertyDescriptor) {
                if (((IndexedPropertyDescriptor) descriptor).getIndexedWriteMethod() == null) {
                    if (log.isDebugEnabled()) {
                        log.debug("Skipping read-only property");
                    }
                    return; // Read-only, skip this property setter
                }
                type = ((IndexedPropertyDescriptor) descriptor).
                    getIndexedPropertyType();
            } else {
                if (descriptor.getWriteMethod() == null) {
                    if (log.isDebugEnabled()) {
                        log.debug("Skipping read-only property");
                    }
                    return; // Read-only, skip this property setter
                }
                type = descriptor.getPropertyType();
            }
        }

        // Convert the specified value to the required type
        Object newValue = null;
        if (type.isArray() && (index < 0)) { // Scalar value into array
            if (value == null) {
                String values[] = new String[1];
                values[0] = (String) value;
                newValue = ConvertUtils.convert((String[]) values, type);
            } else if (value instanceof String) {
                String values[] = new String[1];
                values[0] = (String) value;
                newValue = ConvertUtils.convert((String[]) values, type);
            } else if (value instanceof String[]) {
                newValue = ConvertUtils.convert((String[]) value, type);
            } else {
                newValue = value;
            }
        } else if (type.isArray()) {         // Indexed value into array
            if (value instanceof String) {
                newValue = ConvertUtils.convert((String) value,
                                                type.getComponentType());
            } else if (value instanceof String[]) {
                newValue = ConvertUtils.convert(((String[]) value)[0],
                                                type.getComponentType());
            } else {
                newValue = value;
            }
        } else {                             // Value into scalar
            if ((value instanceof String) || (value == null)) {
                newValue = ConvertUtils.convert((String) value, type);
            } else if (value instanceof String[]) {
                newValue = ConvertUtils.convert(((String[]) value)[0],
                                                type);
//          } else if (ConvertUtils.lookup(value.getClass()) != null) {
//changeLog : yangdongyu@2008-04-10 如果值的类型和setter方法参数类型一致,就不需要在再进行类型转换                
            } else if (value.getClass() != type && ConvertUtils.lookup(value.getClass()) != null) {   
                newValue = ConvertUtils.convert(value.toString(), type);
            } else {
                newValue = value;
            }
        }

        // Invoke the setter method
        try {
            if (index >= 0) {
                PropertyUtils.setIndexedProperty(target, propName,
                                                 index, newValue);
            } else if (key != null) {
                PropertyUtils.setMappedProperty(target, propName,
                                                key, newValue);
            } else {
                PropertyUtils.setProperty(target, propName, newValue);
            }
        } catch (NoSuchMethodException e) {
            throw new InvocationTargetException
                (e, "Cannot set " + propName);
        }

    }

}
